Estudiantes
Después de la gran pandemia del Covid-19, diferentes empresas de turismo tuvieron que realizar cambios en sus paquetes de seguros de viaje que sean más adecuados para el bienestar de los turistas promoviendo nuevas ideas en cuanto a una cobertura del Covid, pero quieren asegurarse de que los clientes estén dispuestos a adquirir este nuevo paquete de seguros. De esta manera se tienen bases de datos que recolectan información que diferencian a los viajeros y si deciden o no comprar un paquete de seguros. Entre esas bases de datos usaremos los datos históricos de los clientes en el periodo del 2019 demostrando el rendimiento y las ventas de este paquete en ese periodo.
Las empresas necesitan optimizar costos gracias a las pérdidas, cambios de consumo y alteraciones de los precios causados durante el covid 19. Esto junto a un impulso en la digitalización y por tanto en la recolección de datos hace más importante que nunca conocer el mercado al que se atiende. Por lo tanto se busca poder predecir qué características de un consumidor hacen más probable que este adquiera el seguro de vida. De esto se hace necesario buscar un modelo que pueda predecir con mayor precisión la propensión de un cliente a comprar el seguro y la importancia de las variables consideradas en esta decisión.
Se buscará implementar algoritmos de clasificación basados en características particulares del cliente que permitan identificar si estaría interesado en comprar el paquete de seguros que ofrece la empresa de turismo. Para esto se explorarán múltiples métodos de clasificación como una regresión logística, knn, árboles de decisión, redes neuronales y svm.
El dataset base fue extraído de: https://www.kaggle.com/datasets/tejashvi14/travel-insurance-prediction-data Se usarán las siguientes variables del dataset:
La variable TravelInsurance será nuestra variable objetivo para poder predecir si un cliente quiere acceder al paquete de seguros de viaje que ofrece la compañía.
Debido a que se utilizaron modelos de clasificación se empleará la matriz de confusión, la metrica de recall, la metrica del acurracy y la precisión. En el caso de la red neuronal se emplea binaria entropía cruzada en la fase de entrenamiento.
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay as plot_confusion_matrix
from sklearn import metrics
from sklearn.tree import DecisionTreeClassifier, plot_tree, DecisionTreeRegressor
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data
from torch.utils.data import DataLoader
from torch.utils.data import TensorDataset
from sklearn import preprocessing
url = 'https://raw.githubusercontent.com/DayaVale/Talleres_Machine_learning/master/Proyecto%203/Dataset/TravelInsurancePrediction.csv'
insuranceData = pd.read_csv(url, sep = ',').dropna()
insuranceData.head()
| Unnamed: 0 | Age | Employment Type | GraduateOrNot | AnnualIncome | FamilyMembers | ChronicDiseases | FrequentFlyer | EverTravelledAbroad | TravelInsurance | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 31 | Government Sector | Yes | 400000 | 6 | 1 | No | No | 0 |
| 1 | 1 | 31 | Private Sector/Self Employed | Yes | 1250000 | 7 | 0 | No | No | 0 |
| 2 | 2 | 34 | Private Sector/Self Employed | Yes | 500000 | 4 | 1 | No | No | 1 |
| 3 | 3 | 28 | Private Sector/Self Employed | Yes | 700000 | 3 | 1 | No | No | 0 |
| 4 | 4 | 28 | Private Sector/Self Employed | Yes | 700000 | 8 | 1 | Yes | No | 0 |
Notemos que el conjunto de datos tiene un tamaño de:
insuranceData.shape
(1987, 10)
Este conjunto de datos cuenta con variables tanto numericas como categóricas.
insuranceData.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1987 entries, 0 to 1986 Data columns (total 10 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 1987 non-null int64 1 Age 1987 non-null int64 2 Employment Type 1987 non-null object 3 GraduateOrNot 1987 non-null object 4 AnnualIncome 1987 non-null int64 5 FamilyMembers 1987 non-null int64 6 ChronicDiseases 1987 non-null int64 7 FrequentFlyer 1987 non-null object 8 EverTravelledAbroad 1987 non-null object 9 TravelInsurance 1987 non-null int64 dtypes: int64(6), object(4) memory usage: 155.4+ KB
insuranceData['Employment Type'].value_counts()
Private Sector/Self Employed 1417 Government Sector 570 Name: Employment Type, dtype: int64
La variable FamilyMembers podria ser cambiada a categórica ya que sus datos podrian darnos más información al quitar el comportamiento ordenado de los datos.
# Cambiar a dummies
insuranceData['FamilyMembers'].value_counts()
4 505 5 426 3 377 6 294 7 178 2 93 8 59 9 55 Name: FamilyMembers, dtype: int64
Notemos que nuestra variable objetivo esta un poco desbalanceada pero no es algo muy grave para este proyecto.
insuranceData['TravelInsurance'].value_counts()
0 1277 1 710 Name: TravelInsurance, dtype: int64
Eliminar Columnas
Tenemos la variable en la cual se encuentran los indices del conjunto de datos, como esta variable no es necesaria la eliminamos del conjunto de datos.
insuranceData = insuranceData.drop(columns= ['Unnamed: 0'])
Volver las variables que sean categoricas a variables dummies.
insuranceData = pd.get_dummies(insuranceData, ['Employment Type','EverTravelledAbroad','FrequentFlyer','GraduateOrNot'], drop_first= True)
insuranceData.head()
| Age | AnnualIncome | FamilyMembers | ChronicDiseases | TravelInsurance | Employment Type_Private Sector/Self Employed | EverTravelledAbroad_Yes | FrequentFlyer_Yes | GraduateOrNot_Yes | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 31 | 400000 | 6 | 1 | 0 | 0 | 1 | 0 | 0 |
| 1 | 31 | 1250000 | 7 | 0 | 0 | 1 | 1 | 0 | 0 |
| 2 | 34 | 500000 | 4 | 1 | 1 | 1 | 1 | 0 | 0 |
| 3 | 28 | 700000 | 3 | 1 | 0 | 1 | 1 | 0 | 0 |
| 4 | 28 | 700000 | 8 | 1 | 0 | 1 | 1 | 1 | 0 |
Estas funciones nos ayudarar a determinar la matriz de confusión y evaluar tres metricas importantes como son el recall, la presición y el acurracy que estan dadas por las siguientes ecuaciones: $$ recall = \frac{TP}{TP+FN}$$
$$presicion = \frac{TP}{TP+FP}$$$$acurracy = \frac{TP+TN}{TP+TN+FP+FN}$$def Matrix_Confusion_metrics(y_pred, y_test):
cm = confusion_matrix(y_test, y_pred)
disp = plot_confusion_matrix(confusion_matrix=cm)
disp.plot()
recall = recall_score(y_test, y_pred, average='binary')
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))
print("presicion:", precision_score(y_test, y_pred))
print('Recall:', recall)
Dividimos el dataset en un conjunto de test y un conjunto de train con los siguientes porcentajes.
# Division en variable objetivo
y = insuranceData['TravelInsurance']
X = insuranceData.drop(columns= ['TravelInsurance'])
# Division de los datos en train y en test
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
train_size = 0.8,
random_state = 42
)
Para realizar tambien una comparación tomamos la variable FamilyMembers y la volvimos categorica, así para tener un poco más de variables. Además tambien realizamos una division del dataset, en los mismos porcentajes de Train y test comentados anteriormente.
# Volvemos la columna FamilyMembers Dummie
X2 = pd.get_dummies(X, columns = ['FamilyMembers'], drop_first=True)
# Dividimos este nuevo dataset X2 en Train y Test
X_train2, X_test2, y_train2, y_test2 = train_test_split(
X2,
y,
train_size = 0.8,
random_state = 42
)
Cuando hablamos de escalamiento y estandarización nos referimos a multiplicar por la media y dividir por la desviación estandar.
Escalamos inicialmente el conjunto X de train y test el cual no se combirtio la variables FamilyMembers en dummies.
# Escalador
scaler_train = preprocessing.StandardScaler()
scaler_test = preprocessing.StandardScaler()
scaler_train.fit(X_train)
scaler_test.fit(X_test)
X_train_scaled = scaler_train.transform(X_train)
X_test_scaled = scaler_test.transform(X_test)
Tambien escalamos El conjunto X2 el cual cuenta con la variable FamilyMemmbers en forma de dummies.
# Escalador
scaler_train2 = preprocessing.StandardScaler()
scaler_test2 = preprocessing.StandardScaler()
scaler_train2.fit(X_train2)
scaler_test2.fit(X_test2)
X_train2_scaled = scaler_train2.transform(X_train2)
X_test2_scaled = scaler_test2.transform(X_test2)
Se desarrollara un modelo de clasificación con un arbol de desición para poder obtener una aproximación inicial a nuestro problema desde el cual comparar la eficiencia de otros modelos de mayor potencia o rigurosidad con un modelo sencillo.
Este primer modelo es con la variable FamilyMembers de manera normal y no dummies. Se empleara el criterio de entropia y todo lo demas se mantendra estandar.
#Modelo de arbol de desición
tree_clf = DecisionTreeClassifier(criterion='entropy', random_state=0)
tree_clf.fit(X_train_scaled, y_train)
DecisionTreeClassifier(criterion='entropy', random_state=0)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
DecisionTreeClassifier(criterion='entropy', random_state=0)
#print("Accuracy de entrenamiento:", modelo.score(X, y))
plt.figure(figsize=(40,20))
plot_tree(tree_clf, filled=True, class_names=True)
plt.title("Decision tree training for training dataset")
plt.show()
Este primer modelo es con la variable FamilyMembers de manera dummies
tree_clf2 = DecisionTreeClassifier(criterion='entropy', random_state=0)
tree_clf2.fit(X_train2_scaled, y_train2)
DecisionTreeClassifier(criterion='entropy', random_state=0)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
DecisionTreeClassifier(criterion='entropy', random_state=0)
#print("Accuracy de entrenamiento:", modelo.score(X, y))
plt.figure(figsize=(40,20))
plot_tree(tree_clf2, filled=True, class_names=True)
plt.title("Decision tree training for training dataset")
plt.show()
Nota: Obtuvimos que en ambos arbol de desición se muestran un poco complejo, donde no se puede determinar a simple vista como es el camino para llegar a una classificación. Algunas ideas que pensamos ver más adelante del proyecto es realizar una podación del arbol o utilizar random forest. Además veremos otros modelos como knn y redes neuronales.
Evaluar el modelo
Primero evaluamos el modelo con las variables normales y escaladas.
# Predicciones dadas por el modelo mediante el X_test
y_tree_pred = tree_clf.predict(X_test_scaled)
El modelo obtuvo una buena presición a pesar a pesar de tener un arbol un poco complejo. Pero es un buen punto de partida para continuar probando diferentes modelos y tecnicas.
Matrix_Confusion_metrics(y_tree_pred, y_test)
Accuracy: 0.8040201005025126 presicion: 0.7560975609756098 Recall: 0.6595744680851063
Ahora, evaluaremos el modelo con la variable FamilyMembers de manera dummies.
y_tree_pred2 = tree_clf2.predict(X_test2_scaled)
Matrix_Confusion_metrics(y_tree_pred2, y_test2)
Accuracy: 0.8040201005025126 presicion: 0.7480314960629921 Recall: 0.6737588652482269
Nota: Notemos que a pesar de que ambos modelos implementados anteriormente tuvieron un mismo valor en la metrica Acurracy los valores dados referentes a las metricas de Recall y Precision variaron es decir que a pesar de que tuvo un buen Acurracy no nos indica que vayan a tener un mejor Recall o presicion. entre estos modelos el que dio mejor metrica entre el recall fue el modelo realizado con la variable FamilyMemmbers como dummie.
En esta sección probaremos nuevos modelos que contribuyan a mejorar la clasificación de nuestra variable objetivo y los cuales puedes ser un poco más complejos pero obtener mejor presición.
Veremos inicialmente el resultado dado al podar el arbol de desición dado anteriormente con los datos que no cuentan con la variable FamilyMembers como dummies.
path = tree_clf.cost_complexity_pruning_path(X_train_scaled, y_train)
ccp_alphas, impurities = path.ccp_alphas, path.impurities
besto = 0
besto_alfa = 0
for i in range(len(ccp_alphas)):
clf = DecisionTreeClassifier(criterion='entropy', random_state=0, ccp_alpha = ccp_alphas[i] )
clf.fit(X_train_scaled, y_train)
y_pred = clf.predict(X_test_scaled)
prec = metrics.accuracy_score(y_test, y_pred)
if prec > besto:
besto = prec
besto_alfa = ccp_alphas[i]
print("Mejor precision es:", besto, "con alfa:", besto_alfa)
Mejor precision es: 0.8467336683417085 con alfa: 0.0020088189663407426
best_tree_clf = DecisionTreeClassifier(criterion='entropy', random_state=0, ccp_alpha = besto_alfa)
best_tree_clf.fit(X_train_scaled, y_train)
y_podadotree_pred = best_tree_clf.predict(X_test_scaled)
plt.figure(figsize=(40,20))
plot_tree(best_tree_clf, filled=True, class_names=True)
plt.title("Decision tree training for training dataset")
plt.show()
Evaluar el modelo
## Metricas a evaluar
Matrix_Confusion_metrics(y_podadotree_pred , y_test)
Accuracy: 0.8467336683417085 presicion: 0.9651162790697675 Recall: 0.5886524822695035
El resultado dado al podar el arbol de desición dado anteriormente con los datos que cuentan con la variable FamilyMembers como dummies.
path = tree_clf.cost_complexity_pruning_path(X_train2_scaled, y_train2)
ccp_alphas, impurities = path.ccp_alphas, path.impurities
besto2 = 0
besto_alfa2 = 0
for i in range(len(ccp_alphas)):
clf = DecisionTreeClassifier(criterion='entropy', random_state=0, ccp_alpha = ccp_alphas[i] )
clf.fit(X_train2_scaled, y_train)
y_pred = clf.predict(X_test2_scaled)
prec = metrics.accuracy_score(y_test2, y_pred)
if prec > besto2:
besto2 = prec
besto_alfa2 = ccp_alphas[i]
print("Mejor precision es:", besto2, "con alfa:", besto_alfa2)
Mejor precision es: 0.8517587939698492 con alfa: 0.0028157296220304925
best_tree_clf2 = DecisionTreeClassifier(criterion='entropy', random_state=0, ccp_alpha = besto_alfa2)
best_tree_clf2.fit(X_train2_scaled, y_train2)
y_podadotree_pred2 = best_tree_clf2.predict(X_test2_scaled)
plt.figure(figsize=(40,20))
plot_tree(best_tree_clf2, filled=True, class_names=True)
plt.title("Decision tree training for training dataset")
plt.show()
Evaluar el Modelo
Matrix_Confusion_metrics(y_podadotree_pred2 , y_test2)
Accuracy: 0.8517587939698492 presicion: 0.9880952380952381 Recall: 0.5886524822695035
Nota: Los modelos anteriores presentan una mejoría significativa con respecto al árbol inicial llegando a una mejor precisión de alrededor de 5 puntos porcentuales. Similarmente la precisión aumenta en gran medida, pero el recall cae. Entre los dos casos, el uso de la cantidad de familiares como una variable categórica presenta mejores resultados.
Este modelo tiene un mejor rendimiento en general que el simple, pero la perdida en recall indica que no es una opción ideal si se tiene un mayor peso a los falsos negativos que a los falsos positivos. Esta condición se traduce a que no es un modelo viable si la empresa prefiere no perder clientes a costa de invertir en publicidad para viajeros que no van a comprar.
Modelo utilizando los datos que no cuentan con la variable FamilyMembers como dummies.
rfor_clf = RandomForestClassifier(random_state=0, criterion='entropy')
rfor_clf.fit(X_train_scaled, y_train)
# Predicciones dadas por el modelo mediante el X_test
y_rfor_pred = rfor_clf.predict(X_test_scaled)
## Metricas y matriz de confusion
Matrix_Confusion_metrics(y_rfor_pred , y_test)
Accuracy: 0.8115577889447236 presicion: 0.7894736842105263 Recall: 0.6382978723404256
Modelo utilizando los datos que cuentan con la variable FamilyMembers como dummies.
rfor_clf2 = RandomForestClassifier(random_state=0, criterion='entropy')
rfor_clf2.fit(X_train2_scaled, y_train2)
# Predicciones dadas por el modelo mediante el X_test
y_rfor_pred2 = rfor_clf2.predict(X_test2_scaled)
Matrix_Confusion_metrics(y_rfor_pred2 , y_test2)
Accuracy: 0.8090452261306532 presicion: 0.782608695652174 Recall: 0.6382978723404256
Nota: El resultado obtenido es ligeramente mejor al obtenido en el modelo inicial. Los cambios en accuracy, precisión y recall no justifican el cambio del modelo. Entre los dos casos para la variable de family members también se encuentra que tiene pocos efectos en el desempeño. Igualmente, el modelo de random forest que obtuvo un mejor acurracy fue al no comvertir la variable Family members pero de resto explican de igual manera.
Para el caso de KNN se realizarán dos análisis de búsqueda de parámetros; se buscará la cantidad de vecinos optima haciendo un barrido desde 1 vecino hasta 99 y se comparara el caso sin pesos con el peso de distancia. De este modo se obtendrá el modelo con mejor accuracy.
Modelo utilizando los datos que no cuentan con la variable FamilyMembers* como dummies.*
scores = []
for i in range(100):
neigh = KNeighborsClassifier(n_neighbors=i+1)
neigh.fit(X_train_scaled, y_train)
scores.append(neigh.score(X_test_scaled,y_test))
plt.plot(scores)
[<matplotlib.lines.Line2D at 0x7f33711f5b10>]
scores=[]
for n in range(1,100):
knn = KNeighborsClassifier(n_neighbors=n, weights='distance')
knn.fit(X_train_scaled,y_train)
s=knn.score(X_test_scaled,y_test)
scores.append(s)
plt.plot(scores)
best_neigh = KNeighborsClassifier(n_neighbors=11)
best_neigh.fit(X_train_scaled, y_train)
y_neigh_pred = best_neigh.predict(X_test_scaled)
Evaluar Modelo
## Metricas y matriz de confusion
Matrix_Confusion_metrics(y_neigh_pred , y_test)
Accuracy: 0.7788944723618091 presicion: 0.7676767676767676 Recall: 0.5390070921985816
Modelo utilizando los datos que cuentan con la variable FamilyMembers como dummies.
scores = []
for i in range(100):
neigh = KNeighborsClassifier(n_neighbors=i+1)
neigh.fit(X_train2_scaled, y_train2)
scores.append(neigh.score(X_test2_scaled,y_test2))
plt.plot(scores)
[<matplotlib.lines.Line2D at 0x7f33710ee890>]
scores=[]
for n in range(1,100):
knn = KNeighborsClassifier(n_neighbors=n, weights='distance')
knn.fit(X_train2_scaled,y_train2)
s=knn.score(X_test2_scaled,y_test2)
scores.append(s)
plt.plot(scores)
best_neigh2 = KNeighborsClassifier(n_neighbors=8)
best_neigh2.fit(X_train2_scaled, y_train2)
y_neigh_pred2 = best_neigh2.predict(X_test2_scaled)
Evaluar Modelo
Matrix_Confusion_metrics(y_neigh_pred2 , y_test2)
Accuracy: 0.7864321608040201 presicion: 0.8181818181818182 Recall: 0.5106382978723404
Nota: En este caso se encuentra un resultado peor que el del modelo inicial de modo que es subóptimo el uso de knn para la solución del problema planteado. Es interesante considerar que estos modelos fueron probados previamente a la escala de los datos, por lo tanto, es posible que para este caso la perdida de magnitudes haya significado una perdida en eficiencia del modelo. Además notemque el número de k-vecinos reduce al utilizar el modelo con la variable FamilyMembers donde este k = 8 y obtiene un mayor Acurracy del 78% y una mayor Presicion con 81% pero un poco menor en la matrica del Recall con 51%. Pero en el otro utilizamos un k = 11 y obtenemos un mayor Recall pero un menor Acurracy de 77% y presicion de 76%.
A continuación, se utilizará el método de Support Vector Machine para la clasificación. Inicialmente se realizará una búsqueda de parámetros óptimos mediante la función GridSearchCV para ambos casos de entradas.
Modelo utilizando los datos que no cuentan con la variable FamilyMembers como dummies.
num_features = np.size(X_train_scaled, axis=1)
param_grid = [
{'C': [1, 10, 100, 1000],
'gamma': [1/num_features, 1, 0.1, 0.01, 0.001, 0.0001],
'kernel': ['rbf']},
]
optimal_params = GridSearchCV(
SVC(),
param_grid,
cv=5,
scoring='roc_auc',
verbose=0
)
optimal_params.fit(X_train_scaled, y_train)
print(optimal_params.best_params_)
{'C': 1000, 'gamma': 0.01, 'kernel': 'rbf'}
clf_svm = SVC(C= 1, gamma= 0.01, kernel= 'rbf')
clf_svm.fit(X_train_scaled, y_train)
y_svm_pred = clf_svm.predict(X_test_scaled)
Evaluar el modelo
## Metricas y matriz de confusion
Matrix_Confusion_metrics(y_svm_pred , y_test)
Accuracy: 0.7462311557788944 presicion: 0.7564102564102564 Recall: 0.41843971631205673
num_features = np.size(X_train2_scaled, axis=1)
param_grid = [
{'C': [1, 10, 100, 1000],
'gamma': [1/num_features, 1, 0.1, 0.01, 0.001, 0.0001],
'kernel': ['rbf']},
]
optimal_params = GridSearchCV(
SVC(),
param_grid,
cv=5,
scoring='roc_auc',
verbose=0
)
optimal_params.fit(X_train2_scaled, y_train2)
print(optimal_params.best_params_)
{'C': 1000, 'gamma': 0.01, 'kernel': 'rbf'}
clf_svm2 = SVC(C= 1, gamma= 0.01, kernel= 'rbf')
clf_svm2.fit(X_train2_scaled, y_train2)
y_svm_pred2 = clf_svm2.predict(X_test2_scaled)
Evaluar el modelo
Matrix_Confusion_metrics(y_svm_pred2 , y_test2)
Accuracy: 0.7462311557788944 presicion: 0.7564102564102564 Recall: 0.41843971631205673
Nota: En este se presenta que solo la precisión se mantiene estable, las otras dos métricas caen haciendo el modelo un mal candidato a solución del problema.
Inicialmente partimos el conjunto de entrenamiento en dos, donde uno sea el cojunto de entrenamiento y el otro el conjunto de validación, en donde sea 80% entrenamiento, 20% validación dando un 64% del total en entrenamiento y 16% en validación. Además escalamos estos datos.
# Particion en conjunto de train y validación
X_train, X_val, y_train, y_val = train_test_split(
X_train,
y_train,
train_size = 0.8,
random_state = 42
)
# Escalamiento de los datos
scaler_train = preprocessing.StandardScaler()
scaler_val = preprocessing.StandardScaler()
scaler_train.fit(X_train)
scaler_val.fit(X_val)
X_train_scaled = scaler_train.transform(X_train)
X_val_scaled = scaler_val.transform(X_val)
Inicialmente se realizan las preparaciones para convertir los datos en datasets de tensores con tal de poder emplear las utilidades de estos como lo es el proceso de backpropagation.
# Preparación de los datos
class MyDataset():
def __init__(self,x,y):
y=y.values
X=x
self.X=torch.tensor(X,dtype=torch.float32)
self.y=torch.tensor(y,dtype=torch.float32)
def __len__(self):
return len(self.y)
def __getitem__(self,idx):
return self.X[idx],self.y[idx]
train_sec=MyDataset(X_train_scaled,y_train)
test_sec=MyDataset(X_test_scaled,y_test)
val_sec=MyDataset(X_val_scaled,y_val)
# Conversion de dataset a DataLoard para poder utilizar las metricas y optimizadores de pythoch
train_data=DataLoader(
train_sec,
batch_size=1,
shuffle=False,
)
test_data=DataLoader(
test_sec,
batch_size=3,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
val_data=DataLoader(
val_sec,
batch_size=3,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
for i, (data, labels) in enumerate(test_data):
print(data.shape, labels.shape)
print(data,labels)
break;
torch.Size([3, 8]) torch.Size([3])
tensor([[-0.5538, -0.4501, 0.2124, 1.6080, 0.6727, 0.4213, -0.4858, -0.4937],
[-1.2568, 1.2623, -0.4281, 1.6080, 0.6727, 0.4213, -0.4858, 2.0255],
[-0.2022, 0.7354, 1.4934, -0.6219, 0.6727, 0.4213, -0.4858, 2.0255]]) tensor([0., 1., 0.])
Desarrollamos una red neuronal de dos capas, la primera es una función lineal con entrada de 8 y una única salida y la segunda es una capa sigmoide. Además, como criterio tomamos Binary Cross entropy loss ya que tenemos únicamente una salida en donde puede ser 0 o 1 y no múltiples. también tomamos el optimizador del descenso del gradiente. El entrenamiento durara 100 épocas para que el modelo se adapte a los datos de manera eficiente evitando underfitting y overfitting.
# Definición de la clase Net
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(8,2)
self.fc2 = nn.Linear(2,1)
self.fc3 = nn.Sigmoid()
def forward(self, x):
x = F.tanh(self.fc1(x))
x = self.fc2(x)
x = self.fc3(x)
return x
model=Net()
optimizer= torch.optim.SGD(model.parameters(), lr=0.1)
criterion= nn.BCELoss()
# Entrenar el modelo
def train_model(model,optimizer,loss_module,train_loader,valid_loader,num_epochs):
valid_loss_min =np.inf
for i in range(num_epochs):
model.train()
train_loss = 0.0
v_loss = 0.0
for data, target in train_loader:
optimizer.zero_grad()
preds = model(data)
preds = preds.squeeze(dim=1)
loss = loss_module(preds, target)
loss.backward()
optimizer.step()
train_loss += loss.item()*data.size(0)
train_loss = train_loss/len(train_loader.dataset)
model.eval()
for data,target in valid_loader:
output=model(data)
target = target.type(torch.LongTensor)
target = target.unsqueeze(1)
valid_loss= criterion(output, target.float())
valid_loss += loss.item()*data.size(0)
valid_loss = valid_loss/len(valid_loader.dataset)
#imprimir estadísticas de entrenamiento y validación
print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
i, train_loss, valid_loss))
#Guardamos el modelo con el menor error de validación.
if valid_loss <= valid_loss_min:
print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...'.format(
valid_loss_min,
valid_loss))
torch.save(model.state_dict(), 'model_1.pt')
valid_loss_min = valid_loss
train_model(model, optimizer,criterion,train_data,val_data,100)
Epoch: 0 Training Loss: 0.553917 Validation Loss: 0.008793 Validation loss decreased (inf --> 0.008793). Saving model ... Epoch: 1 Training Loss: 0.529788 Validation Loss: 0.007624 Validation loss decreased (0.008793 --> 0.007624). Saving model ... Epoch: 2 Training Loss: 0.517088 Validation Loss: 0.007663 Epoch: 3 Training Loss: 0.511992 Validation Loss: 0.007432 Validation loss decreased (0.007624 --> 0.007432). Saving model ... Epoch: 4 Training Loss: 0.509754 Validation Loss: 0.007352 Validation loss decreased (0.007432 --> 0.007352). Saving model ... Epoch: 5 Training Loss: 0.508442 Validation Loss: 0.007309 Validation loss decreased (0.007352 --> 0.007309). Saving model ... Epoch: 6 Training Loss: 0.507527 Validation Loss: 0.007279 Validation loss decreased (0.007309 --> 0.007279). Saving model ... Epoch: 7 Training Loss: 0.506766 Validation Loss: 0.007237 Validation loss decreased (0.007279 --> 0.007237). Saving model ... Epoch: 8 Training Loss: 0.506142 Validation Loss: 0.007201 Validation loss decreased (0.007237 --> 0.007201). Saving model ... Epoch: 9 Training Loss: 0.505685 Validation Loss: 0.007165 Validation loss decreased (0.007201 --> 0.007165). Saving model ... Epoch: 10 Training Loss: 0.505220 Validation Loss: 0.007135 Validation loss decreased (0.007165 --> 0.007135). Saving model ... Epoch: 11 Training Loss: 0.504754 Validation Loss: 0.007115 Validation loss decreased (0.007135 --> 0.007115). Saving model ... Epoch: 12 Training Loss: 0.504290 Validation Loss: 0.007103 Validation loss decreased (0.007115 --> 0.007103). Saving model ... Epoch: 13 Training Loss: 0.503827 Validation Loss: 0.007096 Validation loss decreased (0.007103 --> 0.007096). Saving model ... Epoch: 14 Training Loss: 0.503400 Validation Loss: 0.007086 Validation loss decreased (0.007096 --> 0.007086). Saving model ... Epoch: 15 Training Loss: 0.503024 Validation Loss: 0.007071 Validation loss decreased (0.007086 --> 0.007071). Saving model ... Epoch: 16 Training Loss: 0.502679 Validation Loss: 0.007053 Validation loss decreased (0.007071 --> 0.007053). Saving model ... Epoch: 17 Training Loss: 0.502357 Validation Loss: 0.007035 Validation loss decreased (0.007053 --> 0.007035). Saving model ... Epoch: 18 Training Loss: 0.502056 Validation Loss: 0.007019 Validation loss decreased (0.007035 --> 0.007019). Saving model ... Epoch: 19 Training Loss: 0.501775 Validation Loss: 0.007002 Validation loss decreased (0.007019 --> 0.007002). Saving model ... Epoch: 20 Training Loss: 0.501511 Validation Loss: 0.006986 Validation loss decreased (0.007002 --> 0.006986). Saving model ... Epoch: 21 Training Loss: 0.501260 Validation Loss: 0.006970 Validation loss decreased (0.006986 --> 0.006970). Saving model ... Epoch: 22 Training Loss: 0.501017 Validation Loss: 0.006954 Validation loss decreased (0.006970 --> 0.006954). Saving model ... Epoch: 23 Training Loss: 0.500766 Validation Loss: 0.006938 Validation loss decreased (0.006954 --> 0.006938). Saving model ... Epoch: 24 Training Loss: 0.500480 Validation Loss: 0.006923 Validation loss decreased (0.006938 --> 0.006923). Saving model ... Epoch: 25 Training Loss: 0.500092 Validation Loss: 0.006915 Validation loss decreased (0.006923 --> 0.006915). Saving model ... Epoch: 26 Training Loss: 0.499582 Validation Loss: 0.006924 Epoch: 27 Training Loss: 0.499118 Validation Loss: 0.006936 Epoch: 28 Training Loss: 0.498769 Validation Loss: 0.006944 Epoch: 29 Training Loss: 0.498493 Validation Loss: 0.006945 Epoch: 30 Training Loss: 0.498268 Validation Loss: 0.006941 Epoch: 31 Training Loss: 0.498077 Validation Loss: 0.006935 Epoch: 32 Training Loss: 0.497908 Validation Loss: 0.006927 Epoch: 33 Training Loss: 0.497753 Validation Loss: 0.006919 Epoch: 34 Training Loss: 0.497609 Validation Loss: 0.006911 Validation loss decreased (0.006915 --> 0.006911). Saving model ... Epoch: 35 Training Loss: 0.497474 Validation Loss: 0.006902 Validation loss decreased (0.006911 --> 0.006902). Saving model ... Epoch: 36 Training Loss: 0.497345 Validation Loss: 0.006894 Validation loss decreased (0.006902 --> 0.006894). Saving model ... Epoch: 37 Training Loss: 0.497220 Validation Loss: 0.006886 Validation loss decreased (0.006894 --> 0.006886). Saving model ... Epoch: 38 Training Loss: 0.497099 Validation Loss: 0.006878 Validation loss decreased (0.006886 --> 0.006878). Saving model ... Epoch: 39 Training Loss: 0.496981 Validation Loss: 0.006871 Validation loss decreased (0.006878 --> 0.006871). Saving model ... Epoch: 40 Training Loss: 0.496866 Validation Loss: 0.006864 Validation loss decreased (0.006871 --> 0.006864). Saving model ... Epoch: 41 Training Loss: 0.496752 Validation Loss: 0.006858 Validation loss decreased (0.006864 --> 0.006858). Saving model ... Epoch: 42 Training Loss: 0.496641 Validation Loss: 0.006852 Validation loss decreased (0.006858 --> 0.006852). Saving model ... Epoch: 43 Training Loss: 0.496530 Validation Loss: 0.006847 Validation loss decreased (0.006852 --> 0.006847). Saving model ... Epoch: 44 Training Loss: 0.496421 Validation Loss: 0.006842 Validation loss decreased (0.006847 --> 0.006842). Saving model ... Epoch: 45 Training Loss: 0.496313 Validation Loss: 0.006838 Validation loss decreased (0.006842 --> 0.006838). Saving model ... Epoch: 46 Training Loss: 0.496205 Validation Loss: 0.006835 Validation loss decreased (0.006838 --> 0.006835). Saving model ... Epoch: 47 Training Loss: 0.496099 Validation Loss: 0.006832 Validation loss decreased (0.006835 --> 0.006832). Saving model ... Epoch: 48 Training Loss: 0.495993 Validation Loss: 0.006830 Validation loss decreased (0.006832 --> 0.006830). Saving model ... Epoch: 49 Training Loss: 0.495888 Validation Loss: 0.006828 Validation loss decreased (0.006830 --> 0.006828). Saving model ... Epoch: 50 Training Loss: 0.495784 Validation Loss: 0.006827 Validation loss decreased (0.006828 --> 0.006827). Saving model ... Epoch: 51 Training Loss: 0.495680 Validation Loss: 0.006826 Validation loss decreased (0.006827 --> 0.006826). Saving model ... Epoch: 52 Training Loss: 0.495576 Validation Loss: 0.006826 Validation loss decreased (0.006826 --> 0.006826). Saving model ... Epoch: 53 Training Loss: 0.495473 Validation Loss: 0.006826 Epoch: 54 Training Loss: 0.495371 Validation Loss: 0.006827 Epoch: 55 Training Loss: 0.495269 Validation Loss: 0.006828 Epoch: 56 Training Loss: 0.495167 Validation Loss: 0.006829 Epoch: 57 Training Loss: 0.495066 Validation Loss: 0.006831 Epoch: 58 Training Loss: 0.494966 Validation Loss: 0.006833 Epoch: 59 Training Loss: 0.494867 Validation Loss: 0.006835 Epoch: 60 Training Loss: 0.494768 Validation Loss: 0.006838 Epoch: 61 Training Loss: 0.494670 Validation Loss: 0.006840 Epoch: 62 Training Loss: 0.494573 Validation Loss: 0.006843 Epoch: 63 Training Loss: 0.494477 Validation Loss: 0.006846 Epoch: 64 Training Loss: 0.494383 Validation Loss: 0.006848 Epoch: 65 Training Loss: 0.494289 Validation Loss: 0.006851 Epoch: 66 Training Loss: 0.494197 Validation Loss: 0.006854 Epoch: 67 Training Loss: 0.494107 Validation Loss: 0.006856 Epoch: 68 Training Loss: 0.494017 Validation Loss: 0.006859 Epoch: 69 Training Loss: 0.493930 Validation Loss: 0.006861 Epoch: 70 Training Loss: 0.493843 Validation Loss: 0.006864 Epoch: 71 Training Loss: 0.493758 Validation Loss: 0.006866 Epoch: 72 Training Loss: 0.493675 Validation Loss: 0.006868 Epoch: 73 Training Loss: 0.493592 Validation Loss: 0.006871 Epoch: 74 Training Loss: 0.493511 Validation Loss: 0.006873 Epoch: 75 Training Loss: 0.493432 Validation Loss: 0.006875 Epoch: 76 Training Loss: 0.493353 Validation Loss: 0.006877 Epoch: 77 Training Loss: 0.493276 Validation Loss: 0.006879 Epoch: 78 Training Loss: 0.493199 Validation Loss: 0.006881 Epoch: 79 Training Loss: 0.493124 Validation Loss: 0.006883 Epoch: 80 Training Loss: 0.493050 Validation Loss: 0.006885 Epoch: 81 Training Loss: 0.492977 Validation Loss: 0.006887 Epoch: 82 Training Loss: 0.492905 Validation Loss: 0.006889 Epoch: 83 Training Loss: 0.492833 Validation Loss: 0.006892 Epoch: 84 Training Loss: 0.492763 Validation Loss: 0.006894 Epoch: 85 Training Loss: 0.492692 Validation Loss: 0.006896 Epoch: 86 Training Loss: 0.492623 Validation Loss: 0.006899 Epoch: 87 Training Loss: 0.492554 Validation Loss: 0.006901 Epoch: 88 Training Loss: 0.492486 Validation Loss: 0.006904 Epoch: 89 Training Loss: 0.492418 Validation Loss: 0.006907 Epoch: 90 Training Loss: 0.492350 Validation Loss: 0.006910 Epoch: 91 Training Loss: 0.492282 Validation Loss: 0.006913 Epoch: 92 Training Loss: 0.492215 Validation Loss: 0.006917 Epoch: 93 Training Loss: 0.492147 Validation Loss: 0.006922 Epoch: 94 Training Loss: 0.492079 Validation Loss: 0.006926 Epoch: 95 Training Loss: 0.492010 Validation Loss: 0.006932 Epoch: 96 Training Loss: 0.491941 Validation Loss: 0.006938 Epoch: 97 Training Loss: 0.491870 Validation Loss: 0.006946 Epoch: 98 Training Loss: 0.491797 Validation Loss: 0.006955 Epoch: 99 Training Loss: 0.491722 Validation Loss: 0.006966
Para la prueba del modelo utilizaremos como función de perdida el BSELoss y como metrica de evalución el Acurracy del modelo.
test_loss=0.0
criterion= nn.BCELoss()
for data, target in test_data:
output=model(data)
target = target.type(torch.LongTensor)
target = target.unsqueeze(1)
loss= criterion(output,target.float())
test_loss += loss.item()*data.size(0)
test_loss = test_loss/len(test_data.dataset)
print('Test Loss: {:.6f}\n'.format(test_loss))
model.eval()
total, correct =0,0
for i, data in enumerate(test_data, 0):
inputs, labels = data[0], data[1]
inputs = inputs.view(-1, 8)
outputs = model(inputs)
outputs = (outputs > 0.5).long().squeeze()
total += labels.size(0)
correct += (outputs == labels).sum().item()
print('The testing set accuracy of the network is: %d %%' % (100 * correct / total))
Test Loss: 0.509437 The testing set accuracy of the network is: 76 %
Queremos ver como estan dando las predicciones al tomar dos muestras aleatorias de nuestro dataset y pasarlo por tres diferentes modelos como son nuestro mejor modelo que es el arbol de desición podado con un Acurracy de 84%, dos modelos intermedios como son el random Forest con Acurracy de 81% y la red neuronal con un Acurracy de 76%. Tambien nuestro peor modelo que es SVM con un Acurracy de 74%.
# Unimos las dos variables X y Y
df_all1 = pd.concat([X,y],axis = 1)
# Sacamos dos muetsras
sample1 = df_all1.sample(2)
sample1.head()
| Age | AnnualIncome | FamilyMembers | ChronicDiseases | Employment Type_Private Sector/Self Employed | EverTravelledAbroad_Yes | FrequentFlyer_Yes | GraduateOrNot_Yes | TravelInsurance | |
|---|---|---|---|---|---|---|---|---|---|
| 1068 | 27 | 500000 | 4 | 1 | 0 | 1 | 0 | 0 | 1 |
| 1104 | 34 | 1000000 | 5 | 0 | 1 | 1 | 0 | 0 | 0 |
# Separamos en dos muestras X y y
sample_y = sample1[['TravelInsurance']]
sample_x = sample1.drop(columns = ['TravelInsurance'])
sample_y.head()
| TravelInsurance | |
|---|---|
| 1068 | 1 |
| 1104 | 0 |
# Escalamos las muestras x
scaler_sampleN = preprocessing.StandardScaler()
scaler_sampleN.fit(sample_x)
scaled_sampleN = scaler_sampleN.transform(sample_x)
Arbol de Desición
y_predict = best_tree_clf.predict(scaled_sampleN)
print('Prediccion', y_predict)
print('Original', sample_y)
Prediccion [0 1] Original TravelInsurance 1068 1 1104 0
Random Forest
y_pred = rfor_clf.predict(scaled_sampleN )
print('Prediccion', y_pred)
print('Original', sample_y)
Prediccion [0 1] Original TravelInsurance 1068 1 1104 0
Red Neuronal
#Pasamos nuestros datos sin la muestra para ser preparados.
sample_sec=MyDataset(scaled_sampleN , sample_y)
# Definimos el Sample Data
sample_data=DataLoader(
sample_sec,
batch_size=1,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
outputs = []
for data, target in sample_data:
output=model(data)
for i in range(output.size(0)):
output = (output > 0.5).long().squeeze()
outputs.append(output)
print('Predicciones:',(outputs))
print('Originales',(sample1[['TravelInsurance']]))
Predicciones: [tensor(0), tensor(1)] Originales TravelInsurance 1068 1 1104 0
SVM
y_pred = clf_svm.predict(scaled_sampleN )
print('Prediccion', y_pred)
print('Original', sample_y)
Prediccion [0 0] Original TravelInsurance 1068 1 1104 0
Modelo de Red neurnal
Realizaremos otra red neuronal tomando los datos en los cuales la variable FamilyMembers se tomo como una dummie, unicamente para poder observar en que puede cambien el modelo.Ahora, realizaremos primero la partición de los datos en conjunto de entrenamiento con 80% y conjunto de validación con 20%.
# Particion en conjunto de train y validación
X_train2, X_val2, y_train2, y_val2 = train_test_split(
X_train2,
y_train2,
train_size = 0.8,
random_state = 42
)
# Escalamiento de los datos
scaler_train = preprocessing.StandardScaler()
scaler_val = preprocessing.StandardScaler()
scaler_train.fit(X_train2)
scaler_val.fit(X_val2)
X_train2_scaled = scaler_train.transform(X_train2)
X_val2_scaled = scaler_val.transform(X_val2)
Preparamos los datos y covertimos nuestro dataset a dataloader para utilizar las metricas y funciones de pytoch
# Preparacion datos
class MyDataset():
def __init__(self,x,y):
y=y.values
X=x
self.X=torch.tensor(X,dtype=torch.float32)
self.y=torch.tensor(y,dtype=torch.float32)
def __len__(self):
return len(self.y)
def __getitem__(self,idx):
return self.X[idx],self.y[idx]
train_sec=MyDataset(X_train2_scaled,y_train2)
test_sec=MyDataset(X_test2_scaled,y_test2)
val_sec=MyDataset(X_val2_scaled,y_val2)
# Conversion de dataset a dataloader
train_data=DataLoader(
train_sec,
batch_size=1,
shuffle=False,
)
test_data=DataLoader(
test_sec,
batch_size=3,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
val_data=DataLoader(
val_sec,
batch_size=3,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
for i, (data, labels) in enumerate(test_data):
print(data.shape, labels.shape)
print(data,labels)
break;
torch.Size([3, 14]) torch.Size([3])
tensor([[-0.5538, -0.4501, 1.6080, 0.6727, 0.4213, -0.4858, -0.4937, -0.4937,
-0.6531, 2.0255, -0.3962, -0.2906, -0.1838, -0.1521],
[-1.2568, 1.2623, 1.6080, 0.6727, 0.4213, -0.4858, 2.0255, -0.4937,
1.5312, -0.4937, -0.3962, -0.2906, -0.1838, -0.1521],
[-0.2022, 0.7354, -0.6219, 0.6727, 0.4213, -0.4858, 2.0255, -0.4937,
-0.6531, -0.4937, -0.3962, 3.4407, -0.1838, -0.1521]]) tensor([0., 1., 0.])
El único cambio en la estructura de la red neuronal para este caso será el aumento de las variables de entrada para la capa lineal.
# Definición de la clase Net
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(14,1)
self.fc3 = nn.Sigmoid()
def forward(self, x):
x = F.tanh(self.fc1(x))
x = self.fc3(x)
return x
model=Net()
optimizer= torch.optim.SGD(model.parameters(), lr=0.1)
criterion= nn.BCELoss()
def train_model(model,optimizer,loss_module,train_loader,valid_loader,num_epochs):
valid_loss_min =np.inf
for i in range(num_epochs):
model.train()
train_loss = 0.0
v_loss = 0.0
for data, target in train_loader:
optimizer.zero_grad()
preds = model(data)
preds = preds.squeeze(dim=1)
loss = loss_module(preds, target)
loss.backward()
optimizer.step()
train_loss += loss.item()*data.size(0)
train_loss = train_loss/len(train_loader.dataset)
model.eval()
for data,target in valid_loader:
output=model(data)
target = target.type(torch.LongTensor)
target = target.unsqueeze(1)
valid_loss= criterion(output, target.float())
valid_loss += loss.item()*data.size(0)
valid_loss = valid_loss/len(valid_loader.dataset)
#imprimir estadísticas de entrenamiento y validación
print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
i, train_loss, valid_loss))
#Guardamos el modelo con el menor error de validación.
if valid_loss <= valid_loss_min:
print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...'.format(
valid_loss_min,
valid_loss))
torch.save(model.state_dict(), 'model_2.pt')
valid_loss_min = valid_loss
train_model(model, optimizer,criterion,train_data,val_data,100)
Epoch: 0 Training Loss: 0.562263 Validation Loss: 0.014430 Validation loss decreased (inf --> 0.014430). Saving model ... Epoch: 1 Training Loss: 0.546405 Validation Loss: 0.014836 Epoch: 2 Training Loss: 0.542411 Validation Loss: 0.014845 Epoch: 3 Training Loss: 0.540767 Validation Loss: 0.014671 Epoch: 4 Training Loss: 0.538622 Validation Loss: 0.014556 Epoch: 5 Training Loss: 0.537478 Validation Loss: 0.014531 Epoch: 6 Training Loss: 0.536546 Validation Loss: 0.014496 Epoch: 7 Training Loss: 0.536333 Validation Loss: 0.014496 Epoch: 8 Training Loss: 0.535910 Validation Loss: 0.014484 Epoch: 9 Training Loss: 0.535676 Validation Loss: 0.014475 Epoch: 10 Training Loss: 0.535260 Validation Loss: 0.014465 Epoch: 11 Training Loss: 0.534784 Validation Loss: 0.014455 Epoch: 12 Training Loss: 0.534690 Validation Loss: 0.014449 Epoch: 13 Training Loss: 0.534342 Validation Loss: 0.014445 Epoch: 14 Training Loss: 0.534068 Validation Loss: 0.014441 Epoch: 15 Training Loss: 0.533815 Validation Loss: 0.014439 Epoch: 16 Training Loss: 0.533577 Validation Loss: 0.014436 Epoch: 17 Training Loss: 0.533319 Validation Loss: 0.014434 Epoch: 18 Training Loss: 0.533044 Validation Loss: 0.014432 Epoch: 19 Training Loss: 0.532791 Validation Loss: 0.014430 Epoch: 20 Training Loss: 0.532990 Validation Loss: 0.014430 Validation loss decreased (0.014430 --> 0.014430). Saving model ... Epoch: 21 Training Loss: 0.532663 Validation Loss: 0.014428 Validation loss decreased (0.014430 --> 0.014428). Saving model ... Epoch: 22 Training Loss: 0.532352 Validation Loss: 0.014426 Validation loss decreased (0.014428 --> 0.014426). Saving model ... Epoch: 23 Training Loss: 0.532039 Validation Loss: 0.014424 Validation loss decreased (0.014426 --> 0.014424). Saving model ... Epoch: 24 Training Loss: 0.530551 Validation Loss: 0.014422 Validation loss decreased (0.014424 --> 0.014422). Saving model ... Epoch: 25 Training Loss: 0.530101 Validation Loss: 0.014421 Validation loss decreased (0.014422 --> 0.014421). Saving model ... Epoch: 26 Training Loss: 0.529893 Validation Loss: 0.014420 Validation loss decreased (0.014421 --> 0.014420). Saving model ... Epoch: 27 Training Loss: 0.529731 Validation Loss: 0.014420 Validation loss decreased (0.014420 --> 0.014420). Saving model ... Epoch: 28 Training Loss: 0.529593 Validation Loss: 0.014420 Validation loss decreased (0.014420 --> 0.014420). Saving model ... Epoch: 29 Training Loss: 0.529467 Validation Loss: 0.014420 Epoch: 30 Training Loss: 0.529350 Validation Loss: 0.014420 Epoch: 31 Training Loss: 0.529239 Validation Loss: 0.014420 Epoch: 32 Training Loss: 0.529135 Validation Loss: 0.014420 Epoch: 33 Training Loss: 0.529036 Validation Loss: 0.014420 Epoch: 34 Training Loss: 0.528943 Validation Loss: 0.014421 Epoch: 35 Training Loss: 0.528855 Validation Loss: 0.014421 Epoch: 36 Training Loss: 0.528772 Validation Loss: 0.014421 Epoch: 37 Training Loss: 0.528693 Validation Loss: 0.014421 Epoch: 38 Training Loss: 0.528618 Validation Loss: 0.014421 Epoch: 39 Training Loss: 0.528547 Validation Loss: 0.014421 Epoch: 40 Training Loss: 0.528480 Validation Loss: 0.014421 Epoch: 41 Training Loss: 0.528416 Validation Loss: 0.014421 Epoch: 42 Training Loss: 0.528355 Validation Loss: 0.014421 Epoch: 43 Training Loss: 0.528298 Validation Loss: 0.014421 Epoch: 44 Training Loss: 0.528243 Validation Loss: 0.014421 Epoch: 45 Training Loss: 0.528191 Validation Loss: 0.014421 Epoch: 46 Training Loss: 0.528141 Validation Loss: 0.014421 Epoch: 47 Training Loss: 0.528093 Validation Loss: 0.014421 Epoch: 48 Training Loss: 0.528048 Validation Loss: 0.014421 Epoch: 49 Training Loss: 0.528004 Validation Loss: 0.014421 Epoch: 50 Training Loss: 0.527962 Validation Loss: 0.014421 Epoch: 51 Training Loss: 0.527921 Validation Loss: 0.014421 Epoch: 52 Training Loss: 0.527882 Validation Loss: 0.014421 Epoch: 53 Training Loss: 0.527844 Validation Loss: 0.014421 Epoch: 54 Training Loss: 0.527807 Validation Loss: 0.014422 Epoch: 55 Training Loss: 0.527771 Validation Loss: 0.014422 Epoch: 56 Training Loss: 0.527735 Validation Loss: 0.014422 Epoch: 57 Training Loss: 0.527701 Validation Loss: 0.014422 Epoch: 58 Training Loss: 0.527668 Validation Loss: 0.014422 Epoch: 59 Training Loss: 0.527635 Validation Loss: 0.014422 Epoch: 60 Training Loss: 0.527603 Validation Loss: 0.014422 Epoch: 61 Training Loss: 0.527572 Validation Loss: 0.014422 Epoch: 62 Training Loss: 0.527541 Validation Loss: 0.014422 Epoch: 63 Training Loss: 0.527511 Validation Loss: 0.014422 Epoch: 64 Training Loss: 0.527482 Validation Loss: 0.014422 Epoch: 65 Training Loss: 0.527454 Validation Loss: 0.014422 Epoch: 66 Training Loss: 0.527426 Validation Loss: 0.014422 Epoch: 67 Training Loss: 0.527398 Validation Loss: 0.014422 Epoch: 68 Training Loss: 0.527372 Validation Loss: 0.014422 Epoch: 69 Training Loss: 0.527346 Validation Loss: 0.014422 Epoch: 70 Training Loss: 0.527320 Validation Loss: 0.014422 Epoch: 71 Training Loss: 0.527295 Validation Loss: 0.014422 Epoch: 72 Training Loss: 0.527270 Validation Loss: 0.014422 Epoch: 73 Training Loss: 0.527246 Validation Loss: 0.014422 Epoch: 74 Training Loss: 0.527222 Validation Loss: 0.014422 Epoch: 75 Training Loss: 0.527199 Validation Loss: 0.014422 Epoch: 76 Training Loss: 0.527176 Validation Loss: 0.014422 Epoch: 77 Training Loss: 0.527154 Validation Loss: 0.014422 Epoch: 78 Training Loss: 0.527132 Validation Loss: 0.014422 Epoch: 79 Training Loss: 0.527111 Validation Loss: 0.014422 Epoch: 80 Training Loss: 0.527090 Validation Loss: 0.014422 Epoch: 81 Training Loss: 0.527069 Validation Loss: 0.014422 Epoch: 82 Training Loss: 0.527049 Validation Loss: 0.014422 Epoch: 83 Training Loss: 0.527029 Validation Loss: 0.014422 Epoch: 84 Training Loss: 0.527010 Validation Loss: 0.014422 Epoch: 85 Training Loss: 0.526991 Validation Loss: 0.014422 Epoch: 86 Training Loss: 0.526972 Validation Loss: 0.014422 Epoch: 87 Training Loss: 0.526953 Validation Loss: 0.014422 Epoch: 88 Training Loss: 0.526935 Validation Loss: 0.014422 Epoch: 89 Training Loss: 0.526918 Validation Loss: 0.014422 Epoch: 90 Training Loss: 0.526900 Validation Loss: 0.014422 Epoch: 91 Training Loss: 0.526883 Validation Loss: 0.014422 Epoch: 92 Training Loss: 0.526866 Validation Loss: 0.014422 Epoch: 93 Training Loss: 0.526849 Validation Loss: 0.014422 Epoch: 94 Training Loss: 0.526833 Validation Loss: 0.014422 Epoch: 95 Training Loss: 0.526817 Validation Loss: 0.014422 Epoch: 96 Training Loss: 0.526801 Validation Loss: 0.014422 Epoch: 97 Training Loss: 0.526786 Validation Loss: 0.014422 Epoch: 98 Training Loss: 0.526771 Validation Loss: 0.014422 Epoch: 99 Training Loss: 0.526755 Validation Loss: 0.014422
test_loss=0.0
criterion= nn.BCELoss()
for data, target in test_data:
output=model(data)
target = target.type(torch.LongTensor)
target = target.unsqueeze(1)
loss= criterion(output,target.float())
test_loss += loss.item()*data.size(0)
test_loss = test_loss/len(test_data.dataset)
print('Test Loss: {:.6f}\n'.format(test_loss))
model.eval()
total, correct =0,0
for i, data in enumerate(test_data, 0):
inputs, labels = data[0], data[1]
inputs = inputs.view(-1, 14)
outputs = model(inputs)
outputs = (outputs > 0.5).long().squeeze()
total += labels.size(0)
correct += (outputs == labels).sum().item()
print('The testing set accuracy of the network is: %d %%' % (100 * correct / total))
Test Loss: 0.536526 The testing set accuracy of the network is: 76 %
Nota: En el caso de las redes neuronales es más complicado realizar la visualización de las métricas utilizadas en los otros modelos. Sin embargo, la medición de accuracy indica que el modelo es subóptimo y da un resultado que no justifica cambiar el modelo inicial.
Queremos ver como estan dando las predicciones al tomar dos muestras aleatorias de nuestro dataset y pasarlo por tres diferentes modelos como son nuestro mejor modelo que es el arbol de desición podado con un Acurracy de 85%, dos modelos intermedios como son el random Forest con Acurracy de 80% y la red neuronal con un Acurracy de 76%. Tambien nuestro peor modelo que es SVM con un Acurracy de 74%.
# Unimos las dos variables X y Y
df_all2 = pd.concat([X2,y],axis = 1)
# Sacamos dos muestras
sample = df_all2.sample(2)
sample.head()
| Age | AnnualIncome | ChronicDiseases | Employment Type_Private Sector/Self Employed | EverTravelledAbroad_Yes | FrequentFlyer_Yes | GraduateOrNot_Yes | FamilyMembers_3 | FamilyMembers_4 | FamilyMembers_5 | FamilyMembers_6 | FamilyMembers_7 | FamilyMembers_8 | FamilyMembers_9 | TravelInsurance | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1231 | 34 | 1500000 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
| 187 | 28 | 650000 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
# Dividimos las dos muestras en x y y
sample_y = sample[['TravelInsurance']]
sample_x = sample.drop(columns = ['TravelInsurance'])
sample_y.head()
| TravelInsurance | |
|---|---|
| 1231 | 1 |
| 187 | 0 |
# Escalamos la muestra x
scaler_sampleN = preprocessing.StandardScaler()
scaler_sampleN.fit(sample_x)
scaled_sampleN = scaler_sampleN.transform(sample_x)
Arbol de Desición Podado
y_predict = best_tree_clf2.predict(scaled_sampleN)
print('Prediccion', y_predict)
print('Original', sample_y)
Prediccion [0 0] Original TravelInsurance 1231 1 187 0
Random Forest
y_pred2 = rfor_clf2.predict(scaled_sampleN )
print('Prediccion', y_pred2)
print('Original', sample_y)
Prediccion [0 0] Original TravelInsurance 1231 1 187 0
Red Neuronal
#Pasamos nuestros datos de la muestra para ser preparados.
sample_sec=MyDataset(scaled_sampleN , sample_y)
# Definimos el Sample Data
sample_data=DataLoader(
sample_sec,
batch_size=1,
shuffle=False,
num_workers=0,
collate_fn=None,
pin_memory=False,
)
outputs = []
for data, target in sample_data:
output=model(data)
for i in range(output.size(0)):
output = (output > 0.5).long().squeeze()
outputs.append(output)
print('Predicciones', (outputs))
print('Valores originales',(sample[['TravelInsurance']]))
Predicciones [tensor(1), tensor(0)] Valores originales TravelInsurance 1231 1 187 0
SVM
y_pred2 = clf_svm2.predict(scaled_sampleN )
print('Prediccion', y_pred2)
print('Original', sample_y)
Prediccion [1 0] Original TravelInsurance 1231 1 187 0
A partir del trabajo desarrollado adquirimos las siguientes conclusiones:
Al realizar la estandarización de los datos ayudo a que los modelos mejoraran y tuvieran unas muy buenas metricas las cuales como el Acurracy variaba entre el 70% - 87% . Por otro lado el Recall nos daba datos un poco más pequeños lo que nos indica la habilidad del modelo para encontrar los valores True Positive donde entre más cercano a cero no se esta teniendo una muy buena habilidad en el modelo. Por esta razón destacamos que a pesar de tener un buen Accurrancy no indica que un modelo vaya a tener una buena clasificación de los datos.
Los modelos que más destacaron en sus métricas y resultados según su matriz de confusión fueron los modelos realizados como los árboles de decisión, al podar estos árboles y utilizando ramdom forest, obteniendo unas métricas buenas para la clasificación del modelo. De estos se recomendaría usar los árboles podados en general y el modelo inicial de árbol sin podar en caso de que la clasificación de posibles clientes como no compradores tenga un peso de mayor importancia que la perdida de dinero en marketing para viajeros que no serán clientes. Sin embargo, cabe resaltar la poca observabilidad del proceso de clasificación del árbol sin podar al tener demasiadas hojas y una alta profundidad.
A pesar de que ambas redes neuronales tuvieron un igual valor en el Acurracy notemos que el test loss para la primera red neuronal fue menor, eso nos podria señalar que este puede ser un poco más preciso que el segundo modelo de redes neuronales.
Finalmente, nos dimos cuenta que los modelos que se realizaron con la variable FamilyMembers nos daben unas mejore metricas en general y que al realizar las pruebas con dos muestras teniamos más predicciones acertadas que en los modelos con la variable FamilyMembers original. Además, al escalar los datos tuvimos unos mejores resultados que al no tenerlos escalados.